home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / gtar_hlp.zip / FRETBD.C < prev    next >
Text File  |  1990-01-15  |  12KB  |  365 lines

  1. /*
  2.  
  3. Subj:  Guitarist's Helper
  4.  
  5. Fellow guitarists/bassists:
  6.  
  7. I wrote a program that prints a guitar fretboard diagram, and
  8. labels notes or patterns according command-line args.  I found it
  9. helpful in learning and scales and patterns.
  10.  
  11. The user can specify scale notes directly, or supply a root and
  12. formula for a scale.  Positions on the fretboard diagram may be labled
  13. with a user-defined character if desired (this is good for learning
  14. patterns as opposed to actual note names).  Here's a sample output:
  15.  
  16. synapse /betty/b3/fcg 17> fretbd -i G# 2 2 1 2 2 2
  17.  
  18. Scale = G# A# C C# D# F G
  19.     +       +       +       +       +          + +          +       +       +
  20. -||-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|
  21. -||-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|
  22. G||-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|
  23. -||-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|
  24. -||-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|
  25. -||-F-|---|-G-|-G#|---|-A#|---|-C-|-C#|---|-D#|---|-F-|---|-G-|-G#|---|-A#|---|
  26.  
  27. This is my first posting of code to the net; any comments or
  28. suggestions are welcome.  Please use e-mail replies where appropriate.
  29.  
  30. - Yours truly
  31.  
  32. */
  33. /* ********************************************************************** */
  34. /*
  35.  * FILE:            fretbd.2.c
  36.  * AUTHOR:          Frank C. Guida              Philips Laboratories
  37.  *                  (fcg@philabs.philips.com)   Briarcliff Manor, NY 10510
  38.  *
  39.  * DATE:            Fri Dec 22 10:49:29 1989
  40.  *
  41.  * Please acknowledge the author in any reproduction or modification.
  42.  *
  43.  * SYNOPSIS:        fretbd [-h] [-s] [-m char]
  44.  *                         [-i root interval_list] | [-n note_list]
  45.  *
  46.  * DESCRIPTION:     fretbd prints a guitar fretboard (20 frets)
  47.  *                  and labels notes according to the command-line
  48.  *                  args.  Notes may be entered in upper or lower
  49.  *                  case; use b or # to indicate accidentals.
  50.  *
  51.  * OPTION SUMMARY:  (no args):  print blank fretboard.
  52.  *                         -h:  print this message.
  53.  *                         -s:  use sharps instead of flats as the
  54.  *                              dflt_note_type (use with -i option).
  55.  *                         -m:  use char to mark note positions as
  56.  *                              opposed to letter names.
  57.  *                         -i:  construct scale using specified root
  58.  *                              and intervals (in half-steps).
  59.  *                         -n:  construct scale using specified notes.
  60.  *
  61.  * EXAMPLE:         to print the F#maj scale -
  62.  *                  host> fretbd -i F# 2 2 1 2 2 2
  63.  *
  64.  */
  65. /* ********************************************************************** */
  66.  
  67. #include  <stdio.h>
  68. #include  <ctype.h>
  69. #include  <string.h>
  70.  
  71. #define  HELP_MESSAGE "\
  72.  Use:  fretbd [-h] [-s] [-m char] [-i root interval_list] | [-n note_list]\n\n\
  73.  Option Summary:  (no args):  print blank fretboard.\n\
  74.                          -h:  print this message.\n\
  75.                          -s:  use sharps instead of flats as the\n\
  76.                               dflt_note_type (use with -i option).\n\
  77.                          -m:  use char to mark note positions as\n\
  78.                               opposed to letter names.\n\
  79.                          -i:  construct scale using specified root\n\
  80.                               and intervals (in half-steps).\n\
  81.                          -n:  construct scale using specified notes.\n"
  82.  
  83. #define  OP_HELP       "-h"
  84. #define  OP_SHARPS     "-s"
  85. #define  OP_POS_MARK   "-m"
  86. #define  OP_INTERVALS  "-i"
  87. #define  OP_NOTES      "-n"
  88.  
  89. #define  NUM_FRETS      20         /* numbered 0-19 */
  90. #define  NUM_STRINGS     6         /* numbered 1-6 */
  91. #define  MAX_NOTES      12
  92.  
  93. #define  FLATS           0
  94. #define  SHARPS          1
  95.  
  96. #define  NECK_INDEX "\
  97.     +       +       +       +       +          + +\
  98.           +       +       +\n"
  99.  
  100. /* Basic macros */
  101.  
  102. #define  streq(s1, s2)  (strcmp(s1, s2) == 0)
  103.  
  104. #define  not_option(arg)  !(streq(arg, OP_HELP) ||\
  105.                             streq(arg, OP_SHARPS) ||\
  106.                             streq(arg, OP_POS_MARK) ||\
  107.                             streq(arg, OP_INTERVALS) ||\
  108.                             streq(arg, OP_NOTES))
  109.  
  110. /* function declarations */
  111.  
  112. char   *get_note();
  113. short  note_index();
  114. void   error();
  115. void   print_fretbd();
  116. void   print_note();
  117.  
  118. /* global variables */
  119.  
  120. static char *chrom[2][12] =
  121. { /* 1        2        3   4        5        6        7 */
  122.    {"C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B"},
  123.   /* 0   1    2   3    4   5   6    7   8    9   10   11 */
  124.    {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"}
  125. };
  126.  
  127. char  pos_mark_char = '\0';
  128. unsigned short  note_type;
  129. unsigned short  num_notes = 0;
  130.  
  131. /* ********************************************************************** */
  132.  
  133. main( argc, argv )
  134. int   argc;
  135. char  *argv[];
  136. {
  137.    char   *scale[MAX_NOTES];
  138.    short  note_idx;
  139.    unsigned short  a, i, interval;
  140.    unsigned short  dflt_note_type = FLATS;
  141.  
  142.    for( i=0; i < MAX_NOTES; i++ )  /* initialize scale array */
  143.       scale[i] = "-";
  144.  
  145.    /* Parse and verify command-line args.  Args are checked for
  146.     * consistency with any associated option flag (i.e. if the -i option
  147.     * is given, the following arg should be a valid note name, and
  148.     * subsequent args should be valid intervals or a new option flag).
  149.     */
  150.  
  151.    for( a=1; a < argc; a++ )
  152.    {
  153.       if( streq(argv[a], OP_HELP) )
  154.          error( "", "" );          /* not really an error */
  155.  
  156.       else if( streq(argv[a], OP_SHARPS) )
  157.          dflt_note_type = SHARPS;
  158.  
  159.       else if( streq(argv[a], OP_POS_MARK) )
  160.       {
  161.          if( (a+1 < argc) && not_option(argv[a+1]) )
  162.             sscanf( argv[++a], "%c", &pos_mark_char );
  163.          else
  164.             error( "", "Specify one character for position mark." );
  165.       }
  166.       else if( streq(argv[a], OP_INTERVALS) )
  167.       {
  168.          i = 0;
  169.          while( (a+1 < argc) && not_option(argv[a+1]) )
  170.          {
  171.             if( i == 0 )  /* first arg to -i option should be name of root */
  172.             {
  173.                /* convert case if needed */
  174.  
  175.                if( islower(*(argv[++a])) )
  176.                   *(argv[a]) = toupper( *(argv[a]) );
  177.  
  178.                if( (note_idx = note_index(argv[a])) >= 0 )  /* valid note? */
  179.                {
  180.                   scale[i++] = chrom[note_type][note_idx];
  181.  
  182.                   /* if root is an accidental, the scale should be */
  183.                   /* formed from the same note type, i.e. bs or #s */
  184.  
  185.                   switch( note_idx )
  186.                   {
  187.                   case 1: case 3: case 6: case 8: case 10:  /* accidentals */
  188.                      dflt_note_type = note_type;
  189.                   }
  190.                }
  191.                else
  192.                   error( argv[a], "is not a valid note!" );
  193.             }
  194.             else      /* subsequent args to -i option should be intervals */
  195.             {
  196.                if( sscanf( argv[++a], "%hu", &interval ) == 1 )
  197.                {
  198.                   /* determine new note_idx from last note_idx */
  199.                   note_idx = note_index(scale[i-1]) + (short)interval;
  200.  
  201.                   while( note_idx > 11 )     /* correct any overflow */
  202.                      note_idx =- 12;
  203.  
  204.                   scale[i++] = chrom[dflt_note_type][note_idx];
  205.                }
  206.                else
  207.                   error( argv[a], "is not a valid interval!" );
  208.             }
  209.          }
  210.          num_notes = i;
  211.       }
  212.       else if( streq(argv[a], OP_NOTES) )
  213.       {
  214.          i = 0;
  215.          while( (a+1 < argc) && not_option(argv[a+1]) )
  216.          {
  217.             /* convert case if needed */
  218.  
  219.             if( islower(*(argv[++a])) )
  220.                *(argv[a]) = toupper( *(argv[a]) );
  221.  
  222.             if( note_index(argv[a]) >= 0 )   /* valid note? */
  223.                scale[i++] = argv[a];
  224.             else
  225.                error( argv[a], "is not a valid note!" );
  226.          }
  227.          num_notes = i;
  228.       }
  229.    } /* end of argc loop */
  230.  
  231.    /* print scale */
  232.  
  233.    printf( "Scale =" );
  234.    for( i=0; i < num_notes; i++ )
  235.       printf( " %s", scale[i] );
  236.    printf( " \n" );
  237.  
  238.    print_fretbd( scale );
  239.  
  240.    exit(0);
  241. }
  242.  
  243. /* ********************************************************************** */
  244.  
  245. void  error( item, message )
  246. char  *item, *message;
  247. /* Print error message, help message, and exit. */
  248. {
  249.    fprintf( stderr," %s %s\n", item, message );
  250.    fprintf( stderr, HELP_MESSAGE );
  251.    exit(-1);
  252. }
  253.  
  254.  
  255. /* ********************************************************************** */
  256.  
  257. short  note_index( note )
  258. char  *note;
  259. /* Returns the chromatic scale index of note and sets note_type
  260.  * if note is an accidental; returns -1 if note is not a member
  261.  * of the chromatic scale.
  262.  */
  263. {
  264.    short  i;
  265.  
  266.    for( i=0; i < 12; i++ )
  267.    {
  268.       note_type = FLATS;
  269.       if( streq(note, chrom[note_type][i]) )
  270.          return(i);
  271.       note_type = SHARPS;
  272.       if( streq(note, chrom[note_type][i]) )
  273.          return(i);
  274.    }
  275.    return(-1);
  276. }
  277.  
  278. /* ********************************************************************** */
  279.  
  280. void  print_fretbd( scale )
  281. char  *scale[];
  282. /* Print fretboard, labeling notes in scale[]. */
  283. {
  284.    char  *note;
  285.    register unsigned short  string, fret_idx, fret;
  286.  
  287.    printf( NECK_INDEX );
  288.  
  289.    for( string=1; string <= NUM_STRINGS; string++ )
  290.    {
  291.       switch( string )
  292.       {
  293.       case 2:  fret_idx = 11; break;    /* B */
  294.       case 3:  fret_idx = 7; break;     /* G */
  295.       case 4:  fret_idx = 2; break;     /* D */
  296.       case 5:  fret_idx = 9; break;     /* A */
  297.       default: fret_idx = 4; break;     /* E */
  298.       }
  299.  
  300.       for( fret=0; fret < NUM_FRETS; fret++ )
  301.       {
  302.          note = get_note( fret_idx, scale );
  303.          print_note( note, fret );
  304.  
  305.          fret_idx++;
  306.          while( fret_idx > 11 )
  307.             fret_idx -= 12;
  308.       }
  309.       printf( "\n" );
  310.    }
  311. }
  312.  
  313. /* ********************************************************************** */
  314.  
  315. char  *get_note( fret_idx, scale )
  316. unsigned short  fret_idx;
  317. char  *scale[];
  318. /* Returns note if chrom[][fret_idx] is a member of scale[];
  319.  * returns "-" if chrom[][fret_idx] is not a member of scale[].
  320.  */
  321. {
  322.    register unsigned short  i;
  323.  
  324.    for( i=0; i < num_notes; i++ )
  325.    {
  326.       if( streq( scale[i], chrom[FLATS][fret_idx] ) ||
  327.           streq( scale[i], chrom[SHARPS][fret_idx] ) )
  328.          return( scale[i] );
  329.    }
  330.    return( "-" );
  331. }
  332.  
  333. /* ********************************************************************** */
  334.  
  335. void  print_note( note, fret )
  336. char  *note;
  337. unsigned short  fret;
  338. /* Prints note or specified pos_mark_char, then proper fill chars. */
  339. {
  340.    if( streq( note, "-" ) || (pos_mark_char == '\0') )
  341.    {
  342.       printf( "%s", note );
  343.  
  344.       /* if note is a single-char string, print "-" */
  345.  
  346.       if( (fret > 0) && (*(note + 1) == '\0') )
  347.          printf( "-" );
  348.    }
  349.    else
  350.    {
  351.       printf( "%c", pos_mark_char );
  352.       if( fret > 0 )
  353.          printf( "-" );
  354.    }
  355.  
  356.    switch( fret )                  /* print fret indicators */
  357.    {
  358.    case 0:   printf( "||-" );  return;
  359.    case 19:  printf( "|" );  return;
  360.    default:  printf( "|-" );  return;
  361.    }
  362. }
  363.  
  364. /* ******************************* END ********************************** */
  365.